package com.superbytecode.cloud.tool.excel;

import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.style.column.AbstractColumnWidthStyleStrategy;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Sheet;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * All rights Reserved, Designed By www.super-master.com
 *
 * @ProjectName: beacon-cloud
 * @Package: com.superbytecode.cloud.tool.excel
 * @ClassName: ColumnWidthStyleStrategy
 * @Description: [自适应宽度策略]
 * <p> 根据每列内容宽度自适应调整，宽度最小不低于10，最大不超过25 </p>
 * @Author: [Lance Ting]
 * @Date: 2024/10/22 19:53
 * @Version: V1.0
 * @Copyright: 2024 www.super-master.com Inc. All rights reserved.
 * TODO: 注意,本文件Lance Ting所作,如果转载或使用请标明具体出处!
 **/
public class ColumnWidthStyleStrategy extends AbstractColumnWidthStyleStrategy {
    /**
     * 存储sheet索引：列索引：宽度
     */
    private final Map<Integer, Map<Integer, Integer>> cache = new HashMap<>(2);

    /**
     * @param sheetHolder      表格
     * @param dataList         数据列表
     * @param cell             当前单元格
     * @param head             头
     * @param relativeRowIndex 行索引
     * @param isHead           是否是标题行
     */
    @Override
    protected void setColumnWidth(WriteSheetHolder sheetHolder, List<CellData> dataList, Cell cell, //
                                  Head head, Integer relativeRowIndex, Boolean isHead) {
        boolean needSetWidth = isHead || !CollectionUtils.isEmpty(dataList);
        if (!needSetWidth) {
            return;
        }
        // 计算列宽
        Integer columnWidth = calculateColumnWidth(dataList, cell, isHead);
        if (columnWidth < 0) {
            return;
        }
        // 最大不超过25，最小不小于10
        columnWidth = Math.min(columnWidth, 25);
        columnWidth = Math.max(columnWidth, 10);
        Map<Integer, Integer> maxColumnWidthMap = cache.computeIfAbsent(sheetHolder.getSheetNo(), k -> new HashMap<>(16));
        Integer maxColumnWidth = maxColumnWidthMap.get(cell.getColumnIndex());
        if (maxColumnWidth == null || columnWidth > maxColumnWidth) {
            maxColumnWidthMap.put(cell.getColumnIndex(), columnWidth);
            Sheet sheet = sheetHolder.getSheet();
            sheet.setColumnWidth(cell.getColumnIndex(), columnWidth * 256);
        }
    }

    /**
     * 计算宽度
     *
     * @param dataList 数据列表
     * @param cell     当前单元格
     * @param isHead   是否是标题行
     * @return 列宽
     */
    @SuppressWarnings("rawtypes")
    private Integer calculateColumnWidth(List<CellData> dataList, Cell cell, Boolean isHead) {
        if (isHead) {
            // 列头宽度打个折，当这列数据的宽度都很小时，列头文字会换行以节省空间
            return setTextCellWidth(cell.getStringCellValue()) * 8 / 10;
        }
        CellData cellData = dataList.get(0);
        CellDataTypeEnum cellDataType = cellData.getType();
        if (cellDataType == null) {
            return -1;
        }
        switch (cellDataType) {
            case STRING:
                return setTextCellWidth(cellData.getStringValue());
            case NUMBER:
                return cellData.getNumberValue().toString().getBytes().length;
            case BOOLEAN:
                return cellData.getBooleanValue().toString().getBytes().length;
            case DIRECT_STRING:
            case EMPTY:
            case ERROR:
            case IMAGE:
                break;
        }
        return -1;
    }

    /**
     * 字符串宽度（中文宽度x2）
     */
    private int setTextCellWidth(String value) {
        int chineseLength = (value.getBytes().length - value.length()) / 2;
        int otherLength = value.length() - chineseLength;
        return chineseLength * 2 + otherLength + 1;
    }
}